package connect5.ia;

import java.util.ArrayList;
import java.util.List;

import connect5.Grille;

public class GridAnalyser {

   private static final int MIN_LINE_LENGTH = 5;
   private static final int MIN_COL_LENGTH = 5;

   public long analyseGrid(Grille grid) {

      long cumulMatrixConfigValue = 0;
      long horizontal = 0;
      long vertical = 0;
      long diagonal1 = 0;
      long diagonal2 = 0;

      horizontal = analyseHorizontally(grid);
      vertical = analyseVertically(grid);
      diagonal1 = analyseDiagonaly1(grid);
      diagonal2 = analyseDiagonaly2(grid);
      
      if(horizontal == 2000000000 || vertical == 2000000000 || diagonal1 == 2000000000 || diagonal2 == 2000000000){
    	  return 2000000000;
      }
      if(horizontal == -2000000000 || vertical == -2000000000 || diagonal1 == -2000000000 || diagonal2 == -2000000000){
    	  return -2000000000;
      }

      cumulMatrixConfigValue = horizontal + vertical + diagonal1 + diagonal2;
      return cumulMatrixConfigValue;
   }

   public long analyseHorizontally(Grille grid) {
      Grille temp = grid.clone();

      long matrixConfigValue = 0;

      for (byte[] actualLine : temp.getData()) {

         String lineString = convertByteArrayToString(actualLine);

          int value = evaluateLineConfig(lineString);
          if( value == -2000000000 || value == 2000000000){
        	  return value;
          }
          
          else{
        	  matrixConfigValue += value;
          }
      }

      return matrixConfigValue;
   }

   public long analyseVertically(Grille grid) {

      int nbLine = extractNumberOfLine(grid);
      int nbCol = extractNumberOfColumn(grid);

      Grille invertedGrid = invertGrid(grid, nbLine, nbCol);

      return analyseHorizontally(invertedGrid);
   }

   public long analyseDiagonaly1(Grille grid) {

      int nbLine = extractNumberOfLine(grid);
      int nbCol = extractNumberOfColumn(grid);

      long diagoConfigValue = 0;

      if (nbLine >= MIN_LINE_LENGTH && nbCol >= MIN_COL_LENGTH) {

         int ii = 0;
         int jj = 0;

         while (ii < nbCol - 4) {

            int i = ii;
            int j = 0;
            StringBuilder line = new StringBuilder();

            // prochaine ligne du container
            while (i < nbCol && j < nbLine) {
               // mettre la (i,j) valeurs dans un container
               line.append(grid.get(i, j));
               i++;
               j++;
            }
            ii++;
            diagoConfigValue += evaluateLineConfig(line.toString());
         }

         ii = 0;
         jj = 1;

         while (jj < nbLine - 4) {

            int j = jj;
            int i = 0;
            StringBuilder line = new StringBuilder();
            // prochaine ligne du container
            while (i < nbCol && j < nbLine) {
               // mettre la (i,j) valeurs dans un container
               line.append(grid.get(i, j));
               i++;
               j++;
            }
            jj++;
            diagoConfigValue += evaluateLineConfig(line.toString());
         }

      }

      return diagoConfigValue;
   }

   public long analyseDiagonaly2(Grille grid) {

      int nbLine = extractNumberOfLine(grid);
      int nbCol = extractNumberOfColumn(grid);

      long diagoConfigValue = 0;

      if (nbLine >= MIN_LINE_LENGTH && nbCol >= MIN_COL_LENGTH) {

         int ii = nbCol - 1;
         int jj = nbLine - 1;

         while (ii > 3) {

            int i = ii;
            int j = 0;
            StringBuilder line = new StringBuilder();

            // prochaine ligne du container
            while (i >= 0 && j < nbLine) {
               // mettre la (i,j) valeurs dans un container
               line.append(grid.get(i, j));
               i--;
               j++;
            }
            ii--;
            diagoConfigValue += evaluateLineConfig(line.toString());
         }

         ii = nbCol -1;
         jj = 1;

         while (jj < 3) {

            int j = jj;
            int i = nbCol - 1;
            StringBuilder line = new StringBuilder();
            // prochaine ligne du container
            while (i >= 0 && j < nbLine) {
               // mettre la (i,j) valeurs dans un container
               line.append(grid.get(i, j));
               i--;
               j++;
            }
            jj++;
            diagoConfigValue += evaluateLineConfig(line.toString());
         }

      }

      return diagoConfigValue;
   }

   private int evaluateLineConfig(String lineString) {
      List<Pattern> patternFound = new ArrayList<Pattern>();

      int cumulativeValue = 0;

      for (Pattern p : Pattern.values()) {
          if (lineString.contains(p.BBBBB.getInnerStr())){
          	return -2000000000;
          }
          else if (lineString.contains(p.NNNNN.getInnerStr())){
        	  return 2000000000;
          }
    	  
          if (lineString.contains(p.getInnerStr())) {
            patternFound.add(p);
            cumulativeValue += p.getWeigth();
         }
      }

      return cumulativeValue;
   }

   private int extractNumberOfColumn(Grille srcGrid) {
      return srcGrid.getData()[0].length;
   }

   private int extractNumberOfLine(Grille srcGrid) {
      return srcGrid.getData().length;
   }

   private String convertByteArrayToString(byte[] actualLine) {
      StringBuilder line = new StringBuilder();

      for (byte oneByte : actualLine) {
         if (oneByte == 1)
            line.append('1');
         else if (oneByte == 2)
            line.append('2');
         else
            line.append('0');
      }
      return line.toString();
   }

   private Grille invertGrid(Grille srcGrid, int nbLine, int nbCol) {
      Grille invertedGrid = new Grille(nbLine, nbCol);
      invertedGrid.reset();

      for (int i = 0; i < nbLine; ++i) {
         for (int j = 0; j < nbCol; ++j) {
            invertedGrid.set(j, i, srcGrid.get(i, j));
         }
      }

      return invertedGrid;
   }
}
